namespace RBAC.Write.Api.Application.Handler.BomHandler
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Text;
    using System.Text.Json;
    using MediatR;
    using Microsoft.Extensions.Logging;
    using RBAC.Domain.BomManage;
    using RBAC.ErrorCode;
    using RBAC.Interstructrue.Base;
    using RBAC.Write.Api.Application.Command.BomCommand;
    using RBAC.Write.Api.Application.Command.ERP.MaterialFile; // ImportResultDto

    /// <summary>
    /// BOM主表导入 处理器（配合 DownloadBomImportTemplate 模板）
    /// 模板列：BOM名称（必填）、产品编码（必填）、版本号（可选，默认V1.0）、主单位（可选）、修订说明（可选）
    /// 业务规则：
    /// - 通过产品编码查找产品，获取 ProductId 与 ProductName
    /// - 版本号为空则默认 "V1.0"
    /// - 状态默认 0（草稿）
    /// - 生成唯一BOM编码：BOM + yyMMddHHmmss + 3位序号
    /// </summary>
    public class BomImportHandler : IRequestHandler<BomImportCommand, APIResult<ImportResultDto>>
    {
        private readonly IBaseRepository<Bom> _bomRepo;
        private readonly IBaseRepository<Product> _productRepo;
        private readonly ILogger<BomImportHandler> _logger;

        public BomImportHandler(
            IBaseRepository<Bom> bomRepo,
            IBaseRepository<Product> productRepo,
            ILogger<BomImportHandler> logger)
        {
            _bomRepo = bomRepo;
            _productRepo = productRepo;
            _logger = logger;
        }

        public async Task<APIResult<ImportResultDto>> Handle(BomImportCommand request, CancellationToken cancellationToken)
        {
            var result = new APIResult<ImportResultDto> { Data = new ImportResultDto() };
            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                // 1) 基础校验
                if (string.IsNullOrWhiteSpace(request.Content))
                    return new APIResult<ImportResultDto> { Code = APIEnums.Fail, Msg = "导入内容不能为空", Data = new ImportResultDto() };

                // 2) 解析字符串（支持 JSON 数组或带表头 CSV）
                var rows = await ParseRowsAsync(request.Content);
                if (rows.Count == 0)
                    return new APIResult<ImportResultDto> { Code = APIEnums.Fail, Msg = "未读取到有效数据", Data = new ImportResultDto() };

                // 3) 预加载产品字典（按编码）
                var allProducts = _productRepo.GetAll().Where(p => !p.IsDeleted).ToList();
                var productByCode = allProducts.ToDictionary(p => p.Code ?? string.Empty, p => p);

                // 3.1) 预加载已存在的BOM（按产品Id分组），用于提示“产品已存在BOM”
                var allBoms = _bomRepo.GetAll().Where(b => !b.IsDeleted).ToList();
                var bomByProductId = allBoms
                    .GroupBy(b => b.ProductId)
                    .ToDictionary(g => g.Key, g => g.ToList());

                // 4) 逐行校验并构造实体
                var toInsert = new List<Bom>();
                var nowPrefix = DateTime.Now.ToString("yyMMddHHmmss");
                int seq = 1;
                int rowNo = 1; // 字符串解析从第1条数据开始

                // 批次内去重：相同产品Id不允许重复导入
                var batchProductIds = new HashSet<long>();

                foreach (var r in rows)
                {
                    var errors = new List<string>();

                    var name = r.Name?.Trim() ?? string.Empty;
                    var productCode = r.ProductCode?.Trim() ?? string.Empty;
                    var version = string.IsNullOrWhiteSpace(r.Version) ? null : r.Version!.Trim();
                    var unit = string.IsNullOrWhiteSpace(r.Unit) ? null : r.Unit!.Trim();
                    var revision = string.IsNullOrWhiteSpace(r.RevisionNotes) ? null : r.RevisionNotes!.Trim();

                    if (string.IsNullOrWhiteSpace(name))
                        errors.Add("BOM名称不能为空");
                    if (string.IsNullOrWhiteSpace(productCode))
                        errors.Add("产品编码不能为空");

                    Product? product = null;
                    if (!string.IsNullOrWhiteSpace(productCode))
                    {
                        productByCode.TryGetValue(productCode, out product);
                        if (product == null)
                        {
                            errors.Add($"产品不存在：{productCode}");
                        }
                        else
                        {
                            // 先检查数据库中是否已存在该产品的BOM
                            if (bomByProductId.TryGetValue(product.Id, out var existed) && existed.Any())
                            {
                                var firstBom = existed.First();
                                errors.Add($"产品已存在BOM（产品编码：{productCode}，BOM编码：{firstBom.Code}）");
                            }

                            // 再检查本次导入批次内是否重复
                            if (!batchProductIds.Add(product.Id))
                            {
                                errors.Add($"同一产品重复导入：{productCode}（产品Id：{product.Id}）");
                            }
                        }
                    }

                    if (errors.Any())
                    {
                        result.Data.FailCount++;
                        result.Data.ErrorDetails.Add(new ImportErrorDetail
                        {
                            RowNumber = rowNo,
                            ErrorMessage = string.Join("；", errors),
                            OriginalData = new Dictionary<string, string>
                            {
                                { "BOM名称", name },
                                { "产品编码", productCode },
                                { "版本号", version ?? string.Empty },
                                { "主单位", unit ?? string.Empty },
                                { "修订说明", revision ?? string.Empty }
                            }
                        });
                    }
                    else
                    {
                        var code = $"BOM{nowPrefix}{seq.ToString().PadLeft(3,'0')}";
                        seq++;

                        toInsert.Add(new Bom
                        {
                            Code = code,
                            Name = name,
                            ProductId = product!.Id,
                            ProductName = product!.Name,
                            Version = string.IsNullOrWhiteSpace(version) ? "V1.0" : version!,
                            Unit = unit,
                            RevisionNotes = revision,
                            Status = 0
                        });

                        result.Data.SuccessCount++;
                    }

                    rowNo++;
                }

                // 5) 批量入库
                if (toInsert.Any())
                {
                    _bomRepo.CreateBatch(toInsert);
                }

                // 6) 设置返回状态与消息
                if (result.Data.SuccessCount == 0)
                {
                    result.Code = APIEnums.Fail;
                    result.Msg = $"导入失败，失败{result.Data.FailCount}条";
                }
                else if (result.Data.FailCount > 0)
                {
                    // 只要有失败，Code 置为 Fail，交由控制器返回 500
                    result.Code = APIEnums.Fail;
                    result.Msg = $"部分成功，成功{result.Data.SuccessCount}条，失败{result.Data.FailCount}条";
                }
                else
                {
                    result.Code = APIEnums.Success;
                    result.Msg = $"导入完成，成功{result.Data.SuccessCount}条";
                }
            }
            catch (OperationCanceledException)
            {
                _logger?.LogWarning("BOM导入被取消");
                result.Code = APIEnums.Fail;
                result.Msg = "请求已取消";
            }
            catch (Exception ex)
            {
                _logger?.LogError(ex, "BOM导入异常: {Message}", ex.Message);
                result.Code = APIEnums.Fail;
                result.Msg = "导入失败: " + ex.Message;
            }

            return result;
        }

        private sealed class RowData
        {
            public string? Name { get; set; }
            public string? ProductCode { get; set; }
            public string? Version { get; set; }
            public string? Unit { get; set; }
            public string? RevisionNotes { get; set; }
        }

        private static Task<List<RowData>> ParseRowsAsync(string content)
        {
            // 1) JSON 解析优先，兼容 {"content":"[...]"} 或 {"content":[{...}]} 或 直接数组
            var text = content?.Trim() ?? string.Empty;
            if (!string.IsNullOrEmpty(text))
            {
                try
                {
                    using var doc = JsonDocument.Parse(text);
                    var root = doc.RootElement;

                    // 包装对象：{"content": "[...]"} 或 {"content": [{...}]}
                    if (root.ValueKind == JsonValueKind.Object && root.TryGetProperty("content", out var contentProp))
                    {
                        if (contentProp.ValueKind == JsonValueKind.String)
                        {
                            var inner = contentProp.GetString() ?? string.Empty;
                            inner = inner.Trim();
                            if (!string.IsNullOrEmpty(inner) && (inner.StartsWith("[") || inner.StartsWith("{")))
                            {
                                var rowsFromInner = ParseRowsFromJsonString(inner);
                                if (rowsFromInner.Count > 0) return Task.FromResult(rowsFromInner);
                            }
                        }
                        else if (contentProp.ValueKind == JsonValueKind.Array)
                        {
                            var rowsFromArray = ParseRowsFromJsonArray(contentProp);
                            if (rowsFromArray.Count > 0) return Task.FromResult(rowsFromArray);
                        }
                    }

                    // 根即为数组：[{...}]
                    if (root.ValueKind == JsonValueKind.Array)
                    {
                        var rowsFromArray = ParseRowsFromJsonArray(root);
                        if (rowsFromArray.Count > 0) return Task.FromResult(rowsFromArray);
                    }

                    // 根为对象且可直接映射为 RowData（单条）
                    if (root.ValueKind == JsonValueKind.Object)
                    {
                        var single = ParseRowFromJsonObject(root);
                        if (single != null) return Task.FromResult(new List<RowData> { single });
                    }
                }
                catch
                {
                    // 若 JSON 失败，继续尝试 CSV
                }
            }

            // CSV 解析：首行为表头，支持逗号或制表符分隔
            var list = new List<RowData>();
            var lines = SplitLines(text);
            if (lines.Count == 0) return Task.FromResult(list);

            var header = SplitCsvLine(lines[0]);
            // 标题映射
            int idxName = IndexOf(header, new[] { "BOM名称", "名称", "Name" });
            int idxCode = IndexOf(header, new[] { "产品编码", "ProductCode", "Code" });
            int idxVer = IndexOf(header, new[] { "版本号", "Version" });
            int idxUnit = IndexOf(header, new[] { "主单位", "Unit" });
            int idxRev = IndexOf(header, new[] { "修订说明", "RevisionNotes", "Remark", "备注" });

            foreach (var line in lines.Skip(1))
            {
                if (string.IsNullOrWhiteSpace(line)) continue;
                var cols = SplitCsvLine(line);
                var rd = new RowData
                {
                    Name = GetByIndex(cols, idxName),
                    ProductCode = GetByIndex(cols, idxCode),
                    Version = GetByIndex(cols, idxVer),
                    Unit = GetByIndex(cols, idxUnit),
                    RevisionNotes = GetByIndex(cols, idxRev)
                };
                if (!string.IsNullOrWhiteSpace(rd.Name)
                 || !string.IsNullOrWhiteSpace(rd.ProductCode)
                 || !string.IsNullOrWhiteSpace(rd.Version)
                 || !string.IsNullOrWhiteSpace(rd.Unit)
                 || !string.IsNullOrWhiteSpace(rd.RevisionNotes))
                {
                    list.Add(rd);
                }
            }

            return Task.FromResult(list);
        }

        private static List<RowData> ParseRowsFromJsonString(string json)
        {
            try
            {
                using var innerDoc = JsonDocument.Parse(json);
                var root = innerDoc.RootElement;
                if (root.ValueKind == JsonValueKind.Array)
                {
                    return ParseRowsFromJsonArray(root);
                }
                if (root.ValueKind == JsonValueKind.Object)
                {
                    var rd = ParseRowFromJsonObject(root);
                    return rd == null ? new List<RowData>() : new List<RowData> { rd };
                }
            }
            catch
            {
            }
            return new List<RowData>();
        }

        private static List<RowData> ParseRowsFromJsonArray(JsonElement array)
        {
            var rows = new List<RowData>();
            foreach (var elem in array.EnumerateArray())
            {
                if (elem.ValueKind == JsonValueKind.Object)
                {
                    var rd = ParseRowFromJsonObject(elem);
                    if (rd != null)
                    {
                        // 过滤全空
                        if (!(string.IsNullOrWhiteSpace(rd.Name)
                           && string.IsNullOrWhiteSpace(rd.ProductCode)
                           && string.IsNullOrWhiteSpace(rd.Version)
                           && string.IsNullOrWhiteSpace(rd.Unit)
                           && string.IsNullOrWhiteSpace(rd.RevisionNotes)))
                        {
                            rows.Add(rd);
                        }
                    }
                }
            }
            return rows;
        }

        private static RowData? ParseRowFromJsonObject(JsonElement obj)
        {
            // 将对象的键名做规范化映射（去除中文括号及说明），兼容中文表头
            var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            foreach (var prop in obj.EnumerateObject())
            {
                var key = NormalizeHeader(prop.Name);
                var val = prop.Value.ValueKind == JsonValueKind.String ? prop.Value.GetString() : prop.Value.ToString();
                if (!string.IsNullOrWhiteSpace(key))
                {
                    dict[key] = val ?? string.Empty;
                }
            }

            // 可能的字段名集合（已规范化）
            string? name = GetFirst(dict, new[] { "BOM名称", "名称", "Name" });
            string? code = GetFirst(dict, new[] { "产品编码", "ProductCode", "Code" });
            string? ver = GetFirst(dict, new[] { "版本号", "Version" });
            string? unit = GetFirst(dict, new[] { "主单位", "Unit" });
            string? rev = GetFirst(dict, new[] { "修订说明", "RevisionNotes", "Remark", "备注" });

            // 如果对象本身与 RowData 字段匹配（英文），也直接读取
            if (string.IsNullOrWhiteSpace(name) && obj.TryGetProperty("Name", out var pName) && pName.ValueKind == JsonValueKind.String)
                name = pName.GetString();
            if (string.IsNullOrWhiteSpace(code) && obj.TryGetProperty("ProductCode", out var pCode) && pCode.ValueKind == JsonValueKind.String)
                code = pCode.GetString();
            if (string.IsNullOrWhiteSpace(ver) && obj.TryGetProperty("Version", out var pVer) && pVer.ValueKind == JsonValueKind.String)
                ver = pVer.GetString();
            if (string.IsNullOrWhiteSpace(unit) && obj.TryGetProperty("Unit", out var pUnit) && pUnit.ValueKind == JsonValueKind.String)
                unit = pUnit.GetString();
            if (string.IsNullOrWhiteSpace(rev) && obj.TryGetProperty("RevisionNotes", out var pRev) && pRev.ValueKind == JsonValueKind.String)
                rev = pRev.GetString();

            return new RowData
            {
                Name = string.IsNullOrWhiteSpace(name) ? null : name,
                ProductCode = string.IsNullOrWhiteSpace(code) ? null : code,
                Version = string.IsNullOrWhiteSpace(ver) ? null : ver,
                Unit = string.IsNullOrWhiteSpace(unit) ? null : unit,
                RevisionNotes = string.IsNullOrWhiteSpace(rev) ? null : rev
            };
        }

        private static string NormalizeHeader(string key)
        {
            if (string.IsNullOrWhiteSpace(key)) return string.Empty;
            var s = key.Trim().Trim('"');
            // 去除中文括号（…）内的说明
            int l = s.IndexOf('（');
            int r = s.LastIndexOf('）');
            if (l >= 0 && r > l)
            {
                s = s.Remove(l, r - l + 1);
            }
            return s.Trim();
        }

        private static string? GetFirst(Dictionary<string, string> dict, string[] candidates)
        {
            foreach (var c in candidates)
            {
                var key = NormalizeHeader(c);
                if (dict.TryGetValue(key, out var v))
                    return v;
            }
            return null;
        }

        private static List<string> SplitLines(string text)
        {
            return text.Replace("\r\n", "\n").Replace('\r', '\n').Split('\n', StringSplitOptions.RemoveEmptyEntries).ToList();
        }

        private static List<string> SplitCsvLine(string line)
        {
            // 简单 CSV/TSV 解析：按逗号或制表符分隔，处理双引号包裹
            var delim = line.Contains('\t') && !line.Contains(',') ? '\t' : ',';
            var res = new List<string>();
            var sb = new StringBuilder();
            bool inQuotes = false;
            for (int i = 0; i < line.Length; i++)
            {
                char c = line[i];
                if (c == '"')
                {
                    if (inQuotes && i + 1 < line.Length && line[i + 1] == '"')
                    {
                        sb.Append('"');
                        i++; // skip escaped quote
                    }
                    else
                    {
                        inQuotes = !inQuotes;
                    }
                }
                else if (!inQuotes && c == delim)
                {
                    res.Add(sb.ToString().Trim());
                    sb.Clear();
                }
                else
                {
                    sb.Append(c);
                }
            }
            res.Add(sb.ToString().Trim());
            return res;
        }

        private static int IndexOf(List<string> header, string[] names)
        {
            for (int i = 0; i < header.Count; i++)
            {
                var h = header[i].Trim().Trim('"');
                foreach (var n in names)
                {
                    if (string.Equals(h, n, StringComparison.OrdinalIgnoreCase))
                        return i;
                }
            }
            return -1;
        }

        private static string? GetByIndex(List<string> cols, int idx)
        {
            if (idx < 0 || idx >= cols.Count) return null;
            var v = cols[idx].Trim().Trim('"');
            return string.IsNullOrWhiteSpace(v) ? null : v;
        }
    }
}
